;;; xwl-convenience.el --- convenience and crucial settings

;; Copyright (C) 2007, 2008 William Xu

;; Author: William Xu <william.xwl@gmail.com>

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
;; 02110-1301 USA

;; PATH, exec-path

(cond ((eq system-type 'windows-nt)
       (setq exec-path
             (append exec-path
                     '("c:/cygwin/usr/bin"
                       "c:/cygwin/usr/local/bin"
                       "c:/cygwin/usr/sbin"
                       "c:/cygwin/bin"
                       "C:/Program Files/Microsoft Office/OFFICE11"
                       ))))
      (t
       ;; 从 .bashrc 拷贝来的！
       (setenv "PATH"
               "/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/texbin:/usr/X11/bin:/Users/william/bin/scripts:/Users/william/bin:/sw/bin:/sw/sbin:/usr/X11R6/bin"
               )

       ;;                 (mapconcat 'expand-file-name
       ;;                            '("~/bin"
       ;;                              "/usr/texbin"
       ;;                              "/sw/bin")

       (setenv "TERM" "xterm-color")

       (setq exec-path (split-string (getenv "PATH") ":"))))

(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)

(setq xwl-emacs-start-time (current-time))

(defun xwl-emacs-uptime ()
  (interactive)
  (let* ((diff (time-subtract (current-time) xwl-emacs-start-time))
         (str (format "Emacs started at %s, more than %d days(= %.2f hours) ago"
                      (format-time-string "%Y/%m/%d %H:%M:%S" xwl-emacs-start-time)
                      (time-to-number-of-days diff)
                      (/ (time-to-seconds diff) 3600.0))))
    (message str)))

(condition-case nil
    (progn

(require 'less)

(setq mac-pass-command-to-system nil)

(global-set-key (kbd "C-c v") 'less-minor-mode)
(add-hook 'find-file-hook 'auto-less-minor-mode)
(add-hook 'archive-extract-hooks 'auto-less-minor-mode)
(mapc
 (lambda (hook)
   (add-hook hook 'less-minor-mode-on))
 '(help-mode-hook
   wajig-mode-hook
   wordnet-search-mode-hook
   dictionary-mode-hook
   custom-mode-hook
   ;; apropos-mode-hook ; ??
   emms-playlist-mode-hook
   woman-post-format-hook
   Man-mode-hook
   bbdb-mode-hook))

(defun xwl-toggle-find-file-less ()
  "Toggling opening files with `less-minor-mode' automatically ."
  (interactive)
  (if (memq 'less-minor-mode-on find-file-hook)
      (progn
	(remove-hook 'find-file-hook 'less-minor-mode-on)
	(remove-hook 'archive-extract-hooks 'less-minor-mode-on)
	(remove-hook 'after-revert-hook 'less-minor-mode-on)
	(message "Less minor mode after opening file disabled"))
    (add-hook 'find-file-hook 'less-minor-mode-on)
    (add-hook 'archive-extract-hooks 'less-minor-mode-on)
    (add-hook 'after-revert-hook 'less-minor-mode-on)
    (message "Less minor mode after opening file enabled")))

(global-set-key (kbd "C-c n v") 'xwl-toggle-find-file-less)

(add-hook 'find-file-hook 'less-minor-mode-on)
(add-hook 'after-revert-hook 'less-minor-mode-on)

;; (defun xwl-before-revert-hook ()
;;   (if less-minor-mode
;;       (add-hook 'after-revert-hook 'less-minor-mode-on)
;;     (remove-hook 'after-revert-hook 'less-minor-mode-on)))

;; (add-hook 'before-revert-hook 'xwl-before-revert-hook)

(add-hook 'Info-mode-hook 'less-minor-mode-on)

)

(error "Oops! less not found"))

(mouse-avoidance-mode 'animate)

;; cursor/page movements
;; ---------------------

;; "f" in vi(go to char)
(defun xwl-forward-char (n char)
  "Move forward to Nth occurence of CHAR.  Typing `xwl-forward-char-key'
again will move forwad to the next Nth occurence of CHAR."
  (interactive "p\ncForward to char: ")
  (search-forward (string char) nil nil n)
  (while (char-equal (read-char)
		     char)
    (search-forward (string char) nil nil n))
  (setq unread-command-events (list last-input-event)))

(defun xwl-backward-char (n char)
  "Move backward to Nth occurence of CHAR.  Typing `xwl-backward-char-key'
again will move forwad to the next Nth occurence of CHAR."
  (interactive "p\ncBackward to char: ")
  (search-backward (string char) nil nil n)
  (while (char-equal (read-char)
		     char)
    (search-backward (string char) nil nil n))
  (setq unread-command-events (list last-input-event)))

(global-set-key (kbd "C-o") 'xwl-forward-char)
(global-set-key (kbd "M-o") 'xwl-backward-char)

;; date
;; ----

(defun xwl-insert-date ()
  (interactive)
  (insert (xwl-get-date)))

(defun xwl-get-date ()
  (format-time-string "%Y/%m/%d" (current-time)))
  ;; (format-time-string "%Y/%m/%d" (current-time)))

(defun xwl-update-date ()
  "Auto update '[Ll]ast [Uu]pdated:' part if exists when saving.
This should not affect `buffer-undo-list'."
  (interactive)
  (let ((old-list buffer-undo-list))
    (save-excursion
      (beginning-of-buffer)
      (when (search-forward-regexp "Last\\ updated:" nil t)
        (xwl-delete-line)
        (insert " ")
        (xwl-insert-date)))
    (setq buffer-undo-list old-list))
  nil)


(global-set-key (kbd "C-c m d") 'xwl-insert-date)

(add-hook 'before-save-hook 'xwl-update-date)

(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
(setq x-select-enable-clipboard t)

(prefer-coding-system 'utf-8)

;; (require 'auto-enca)
(setq file-coding-system-alist
      '(("\\.dz\\'" no-conversion . no-conversion)
	("\\.g?z\\(~\\|\\.~[0-9]+~\\)?\\'" no-conversion . no-conversion)
	("\\.tgz\\'" no-conversion . no-conversion)
	("\\.tbz\\'" no-conversion . no-conversion)
	("\\.bz2\\'" no-conversion . no-conversion)
	("\\.Z\\(~\\|\\.~[0-9]+~\\)?\\'" no-conversion . no-conversion)
	("\\.elc\\'" emacs-mule . emacs-mule)
	("\\.utf\\(-8\\)?\\'" . utf-8)
	("\\(\\`\\|/\\)loaddefs.el\\'" raw-text . raw-text-unix)
	("\\.tar\\'" no-conversion . no-conversion)
	("\\.po[tx]?\\'\\|\\.po\\." . po-find-file-coding-system)
	("\\.\\(tex\\|ltx\\|dtx\\|drv\\)\\'" . latexenc-find-file-coding-system)

        ;; ("" undecided)
	("" utf-8 . utf-8)
        ;; ("" . enca-detect-coding)
        ))

(defun xwl-revert-buffer-with-coding-system ()
  "Revert buffer with 'gbk coding."
  (interactive)
  (revert-buffer-with-coding-system 'gb2312))

(global-set-key (kbd "C-c n r") 'xwl-revert-buffer-with-coding-system)

(setq auto-mode-alist
      (append
       `(,@(mapcar (lambda (arg)
		     (cons (concat (regexp-opt `(,(car arg))) "$")
			   (cadr arg)))
		   '((".h"    c++-mode)
		     (".lrc"  emms-lyrics-mode)
		     (".sh"   shell-script-mode)
		     ;; (".m"    octave-mode)
		     (".java" java-mode)
		     (".l"    c-mode)
		     (".jl"   sawfish-mode)
                     (".hs"  haskell-mode)
                     ))
         ("fonts.conf" . xml-mode)
	 ("\\(rc\\|.conf\\)$"   . conf-mode)
	 ("\\(.mac\\|.lst\\)$"  . asm-mode)
	 ("\\(.html\\|.htm\\)$" . html-mode)
         ("[sS][cC]onstruct" . python-mode))
       auto-mode-alist))

(add-to-list 'auto-mode-alist '("Makefile.*" . makefile-mode))

(setq image-file-name-regexps
      (mapcar (lambda (el)
                (concat "\\." el "$"))
              '("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" "xpm"
                "pbm" "pgm" "ppm" "pnm")))

;; (add-hook 'text-mode-hook 'turn-on-auto-fill)
(setq-default auto-fill-function 'do-auto-fill)
;; (setq default-justification 'full)
(setq default-fill-column 80 ; 72
      adaptive-fill-regexp
      "[	]*\\([-|#;>*]+[	]*\\|(?[0-9]+[.)][	]*\\)*"
      adaptive-fill-first-line-regexp "\\`[	]*\\'"
      fill-column 80); 72)
(show-paren-mode 1)

;;(unless window-system
;;  (set-face-background 'highlight "red")
;;  (set-face-background 'show-paren-match-face "yellow"))

(menu-bar-mode -1)
(setq column-number-mode t
      line-number-mode t)
(setq show-paren-style 'expression
      scroll-step 1
      scroll-margin 3
      scroll-conservatively 10000
      hscroll-step 1
      hscroll-margin 3)

(setq global-auto-revert-non-file-buffers t)
(global-auto-revert-mode 1)

;; colors & faces
(global-font-lock-mode t)
(setq font-lock-maximum-decoration t)

;; hippie-expand
(setq hippie-expand-try-functions-list
      '(try-expand-dabbrev
	try-expand-whole-kill
;;	senator-try-expand-semantic
	try-expand-dabbrev-visible
	try-expand-dabbrev-from-kill
	try-expand-dabbrev-all-buffers
	try-expand-all-abbrevs
	try-complete-file-name-partially
	try-complete-file-name
	try-expand-list
;	try-complete-lisp-symbol-partially
;;	try-complete-lisp-symbol
        try-expand-line
	try-expand-line-all-buffers))

;; deal with large buffer
;; (setq font-lock-support-mode 'fast-lock-mode)
;; (setq font-lock-support-mode 'lazy-lock-mode
;;       lazy-lock-defer-on-scrolling t
;;       font-lock-maximum-decoration t)
;; (setq font-lock-maximum-size
;;       '((c-mode . 256000)
;; 	(c++-mode . 256000)
;; 	(rmail-mode . 1048576)
;; 	(tex-mode . 1048576)))

(defun his-one-whitespace-between-ce (&optional start end)
  "Automatically insert a whitespace between Chinese and English,
Chinese and digits, which is useful when editing TeX files."
  (interactive)
  (save-excursion
    (unless start (setq start (point-min)))
    (unless end (setq end (point-max)))
    (goto-char start)
    (while (re-search-forward "\\(\\cc\\)\\([0-9a-zA-Z]\\)" end t)
      (replace-match "\\1 \\2" nil nil))
    (goto-char start)
    (while (re-search-forward "\\([0-9a-zA-Z]\\)\\(\\cc\\)" end t)
      (replace-match "\\1 \\2" nil nil))))

(global-set-key (kbd "C-c m o") 'his-one-whitespace-between-ce)

;; (redefined)Use file's full path as buffer name when opening files
;; with same names.

;; (defun create-file-buffer (filename)
;;   (let ((lastname (file-name-nondirectory filename)))
;;     (if (string= lastname "")
;;     (setq lastname filename))
;;     (if (get-buffer lastname)
;;         (generate-new-buffer filename)
;;       (generate-new-buffer lastname))))

;; Alternatively, add the following to custom-set-variables, so it'll
;; show a/c or b/c to make c under a, b distinguishable, without
;; displaying the whole path name.
;;
;;     '(uniquify-buffer-name-style (quote forward) nil (uniquify))

;; battery
;; -------

(require 'battery)
(setq battery-mode-line-format "[%b%p%% %t]")

(when (fboundp 'battery-status-function)
  (setq battery-mode-line-string
        (battery-format battery-mode-line-format
                        (funcall battery-status-function)))

  (defadvice battery-update-handler (around check-on-line)
    "If on-line (not using battery), don't display on mode line."
    (if (>=  (string-to-number
              (battery-format "%p" (funcall battery-status-function)))
             90)
        (progn
          (setq battery-mode-line-string "")
          (force-mode-line-update))
      ad-do-it))

  (ad-activate 'battery-update-handler)

  (run-with-timer 0 battery-update-interval 'battery-update-handler))

;; occur
(defun xwl-occur-previous-line ()
  (interactive)
  (previous-line 1)
  (occur-mode-goto-occurrence)
  (other-window 1))

(defun xwl-occur-next-line ()
  (interactive)
  (next-line 1)
  (occur-mode-goto-occurrence)
  (other-window 1))

(define-key occur-mode-map (kbd "p") 'xwl-occur-previous-line)
(define-key occur-mode-map (kbd "n") 'xwl-occur-next-line)
(define-key occur-mode-map (kbd "M-p") 'xwl-scroll-down-one-line)
(define-key occur-mode-map (kbd "M-n") 'xwl-scroll-up-one-line)
(define-key occur-mode-map (kbd "q")
  '(lambda () (interactive) (delete-windows-on (buffer-name))))


;;; WINDOW

;; redo and undo
(winner-mode 1)

;; jump by name
;; (require 'winring)
;; (winring-initialize)

;; (setq winring-show-names nil)
;; (define-key winring-map "n" 'winring-next-configuration)
;; (define-key winring-map "o" 'winring-new-configuration)

;; jump by registers
;; C-x r w
;; C-x r j

(setq default-directory "~/")

(setq canlock-password "ac9f2efab48b539dd67c289f5eb50f1721edbd74")

;; general
;; -------

(defun xwl-chmod-file-executable ()
  "Make scripts executable if necessary."
  (let ((filename (buffer-file-name))
	(cmd (shell-command-to-string
	      "which -a sh bash expect perl octave guile scsh python dtrace"))
	(exec-signal nil))

    (setq exec-signal
	  (concat "^#!\\ ?\\("
		  (replace-regexp-in-string "\n" "\\|"
					    (substring cmd 0 (1- (length cmd))) nil t)
		  "\\)"))

    ;; shell-command returns 0 if succeeds, or positive digit if fails.
    (save-excursion
      (goto-char (point-min))
      (if (looking-at exec-signal)
	  ;; executable already or tramp file ?
	  (if (or (zerop (shell-command (concat "test -x " filename)))
                  (file-remote-p (buffer-file-name)))
	      (message (concat "Wrote " filename))
	    (progn
	      (shell-command (concat "chmod u+x " filename))
	      (message (concat "Wrote and made executable " filename))))
	(message (concat "Wrote " filename))))))

(defun xwl-after-save-hook ()
  (xwl-chmod-file-executable))

(add-hook 'after-save-hook 'xwl-after-save-hook)

(defun his-scheme-eval-last-sexp (&optional insert)
  (interactive "P")
  (let ((standard-output (if insert (current-buffer) t))
        (cmd (buffer-substring (save-excursion (backward-sexp) (point)) (point))))
    (with-temp-buffer
      (comint-redirect-send-command-to-process
       cmd (current-buffer) (get-process "scheme") t nil)
      (while (string= (buffer-string) "") (sleep-for 0.01))
     (princ (buffer-string)))))

(defun xwl-run-scsh (&optional scheme?)
  "`run-scsh', rename it to scsh.

If SCHEME?, `run-scheme'."
  (interactive "P")
  (if scheme?
      (run-scheme "mzscheme")
    (progn
      (run-scsh nil)
      (rename-buffer "*scsh*"))))

;; todo
;; (setq todo-file-do   "~/.todo/do"
;;       todo-file-done "~/.todo/done"
;;       todo-file-top  "~/.todo/top")

;; (defun xwl-todo-find-do ()
;;   "Visit `todo-file-do' by turning off `less-minor-mode'."
;;   (interactive)
;;   (find-file todo-file-do)
;;   (less-minor-mode -1))

;; (defun xwl-todo-forward-category ()
;;   "Move forward category in current todo buffer."
;;   (interactive)
;;   (end-of-line)
;;   (search-forward-regexp (regexp-opt '("*/* --- ")) nil t)
;;   (beginning-of-line))

;; (defun xwl-todo-backward-category ()
;;   "Move backward category in current todo buffer."
;;   (interactive)
;;   (beginning-of-line)
;;   (search-backward-regexp (regexp-opt '("*/* --- ")) nil t)
;;   (beginning-of-line))

;; (defun xwl-todo-mode-hook ()
;;   (highlight-regexp (concat "^" (regexp-opt '("*/* --- ")) ".*")
;;                     'font-lock-constant-face)
;;   (local-set-key (kbd "a") 'todo-add-category)
;;   (local-set-key (kbd "i") 'todo-insert-item-here)
;;   (local-set-key (kbd "I") 'todo-insert-item)
;;   (local-set-key (kbd "e") 'todo-edit-item)
;;   (local-set-key (kbd "D") 'todo-delete-item)
;;   (local-set-key (kbd "=") 'todo-forward-category)
;;   (local-set-key (kbd "q") 'next-buffer)
;;   (local-set-key (kbd "^")
;;                  (lambda () (interactive)
;;                    (todo-quit)
;;                    (xwl-todo-find-do)
;;                    (goto-char (point-min))))
;;   (local-set-key (kbd "N") 'xwl-todo-forward-category)
;;   (local-set-key (kbd "P") 'xwl-todo-backward-category))

;; (add-hook 'todo-mode-hook 'xwl-todo-mode-hook)
;;todo-categories

;; abbreviations
(setq save-abbrevs t)

(condition-case nil
    (quietly-read-abbrev-file)
  (error nil))

(abbrev-mode t)

;; key solutions: C-up, C-down, etc.
;;(unless window-system
;;  (load "linux")
;;  (load "kn-prefix")
;;  (load "kn-prefix-autoloads"))

;; back up
(setq version-control t
      kept-old-versions 2
      kept-new-versions 3
      delete-old-versions t
      backup-by-copying t
      backup-by-copying-when-linked t
      backup-by-copying-when-mismatch t)

(setq backup-directory-alist
      '(("." . "~/var/emacs_backups" )))

;; compilation-mode, grep-find
;; (defun xwl-compilation-mode-hook ()
;;     (define-key compilation-mode-map (kbd "p") 'previous-line)
;;     (define-key compilation-mode-map (kbd "n") 'next-line)
;;     (define-key compilation-mode-map (kbd "q") 'xwl-hide-buffer))

;; (add-hook 'compilation-mode-hook 'xwl-compilation-mode-hook)
;; tramp
;; tramp (setq file-name-handler-alist nil)
; /telnet:william@localhost:~/

;; /ftp:movie9@denniszz.net9.org#9021:/

;; (setq tramp-default-method-alist
;;       '(("" "%" "smb")
;; 	("" "\\`\\(anonymous\\|ftp\\)\\'" "ftp")
;; 	("^ftp" "" "ftp")
;; 	("\\`localhost\\'" "\\`root\\'" "sudo")))

;; (setq password-cache-expiry 300)

;; (setq tramp-auto-save-directory "~/.tramp-auto-save-directory")

;; (require 'ange-ftp)
;;(setq ange-ftp-ftp-program-args
;;      (cons "-p" ange-ftp-ftp-program-args))

;; /sudo:root@localhost:/etc/X11/

;; flyspell
;; (add-hook 'c-mode-common-hook 'flyspell-prog-mode 1)
;; (add-hook 'cperl-mode-hook    'flyspell-prog-mode 1)
;; (add-hook 'makefile-mode-hook 'flyspell-prog-mode 1)
;; (add-hook 'python-mode-hook   'flyspell-prog-mode 1)
;; (add-hook 'sh-mode-hook       'flyspell-prog-mode 1)

;; dired
(defun xwl-dired-w3m-find-file ()
  (interactive)
  (let ((file (file-name-nondirectory (dired-get-filename))))
    (if (y-or-n-p (format "Use emacs-w3m to browse %s? " file))
	(w3m-find-file file))))

(defun xwl-dired-get-filename-no-extention ()
  "In dired, return the filename without extentions. eg.
\"abc.txt\"  --> \"abc\". Right now the filename should only
be with length 3 extentions !"
  (interactive)
  (let ((filename (file-name-nondirectory (dired-get-filename))))
    (message (substring filename 0 (- (length filename) 4)))))

;;   (set-process-sentinel (get-buffer-process (current-buffer))
;; 			#'xwl-shell-mode-kill-buffer-on-exit))
;; (defun xwl-shell-mode-kill-buffer-on-exit (process state)
;;   (kill-buffer (current-buffer)))

;; xwl-metafont-mode-hook
(defun xwl-metapost-mode-hook ()

  ;;   (defun xwl-metapost-mptopdf ()
  ;;     (interactive)
  ;;     (shell-command (concat "mptopdf " (buffer-file-name))))

  (defun xwl-metapost-preview (STR)
    (interactive "sPreview fig-")
    (let* ((file (file-name-sans-extension
		  (file-name-nondirectory (buffer-file-name))))
	   (file-pdf (concat file "-" STR ".pdf")))
      (shell-command (concat "xpdf " file-pdf))))

  (defun xwl-metapost-pdftopng ()
    (interactive)
    (let* ((file (file-name-sans-extension
		  (file-name-nondirectory (buffer-file-name))))
	   (i 1)
	   (file-pdf (concat file "-" (int-to-string i) ".pdf"))
	   (file-png (concat file "-" (int-to-string i) ".png")))

      (while (file-exists-p file-pdf)
	(if (file-newer-than-file-p file-pdf file-png)
	    (shell-command (concat "pdftoppm " file-pdf " tmp;\
                  convert tmp-000001.ppm " file-png ";\
                  rm -f tmp-000001.ppm")))
	(setq i (1+ i)
	      file-pdf (concat file "-" (int-to-string i) ".pdf")
	      file-png (concat file "-" (int-to-string i) ".png")))

      (message (concat file "-*.pdf have been converted to " file "-*.png."))))

  (auto-revert-mode -1)

  (xwl-text-mode-hook)
  ;;   (local-set-key (kbd "<C-up>") 'xwl-metapost-mptopdf)
  (local-set-key (kbd "<C-down>") 'xwl-metapost-preview)
  (local-set-key (kbd "<C-left>") 'xwl-metapost-pdftopng))

;; (autoload 'typing-of-emacs "The Typing Of Emacs, a game." t)

;; (require 'faith)

;; fvwm-mode
(autoload 'fvwm-mode "fvwm-mode" "Mode for editing fvwm files" t)

;; visual blank, tab, end-of-line ?
;(require 'blank-mode)

;; (require 'tex-info)
(defun xwl-texinfo-mode-compile ()
  (interactive)
  (save-excursion
    (let ((inhibit-read-only t))
      (goto-char (point-min))
      (while (search-forward "@menu" nil t)
        (texinfo-make-menu))
      (save-buffer)
      (makeinfo-buffer)
      (delete-other-windows))))

;; metafont
(add-hook 'metapost-mode-hook 'xwl-metapost-mode-hook)

;; mmm-mode
;; (set-face-background 'mmm-code-submode-face nil)
;; (set-face-background 'mmm-default-submode-face nil)

;; enable tab completion for `shell-command'.
;; (setq shell-command-enable-completions t)
;; (shell-command-activate-advices)
;; (setq shell-command-prompt "%w%$ ")

;; fortune
(defun xwl-fortune-of-the-day ()
  "$ fortune-zh"
  (interactive)
  (message
   (ansi-color-filter-apply
    (shell-command-to-string "fortune-zh"))))

(global-set-key (kbd "C-c m f") 'xwl-fortune-of-the-day)

;; named-let, Thanks to Riastradh@#emacs
(defmacro his-named-let (name parameters &rest body)
  `(labels
       ((,name ,(mapcar 'car parameters) ,@body))
     (,name ,@(mapcar 'cadr parameters))))

(defun xwl-term (&optional create)
  (interactive)
  (cond
   (create
    (term "/bin/bash")
    (rename-buffer "*terminal*" t))
   ((not (get-buffer "xwl-term"))
    (term "/bin/bash")
    (rename-buffer "xwl-term" t))
   (t (switch-to-buffer "xwl-term"))))

;; Chinese
;; -------

;; FIXME: this doesn't work under mac?
;;(require 'chinese-gbk)
;;(when window-system
;;    (require 'characters-gbk)
;;    (require 'fontset-gbk)
    ;; use Chinese instead of Japanese charsets to decode utf-8
    ;;   (require 'gbk-utf-mode)
    ;;   (utf-translate-cjk-mode 1))
;;    )

;; (when (string= (substring emacs-version 0 2) "21")
;;   (set-terminal-coding-system 'chinese-gbk)
;;   (set-keyboard-coding-system 'chinese-gbk))

(setq xwl-default-directories
      '("~/"
        "/ssh:william@ananas:~/"
        "/sudo::/"
        "/ftp:williamxu@ftp.net9.org:/"))

;; octave
(autoload 'octave-help "octave-hlp" nil t)

;; sawfish
; (load-file "/usr/share/emacs/site-lisp/sawfish/sawfish.el") ; oops
(autoload 'sawfish-mode "sawfish" "sawfish-mode" t)
(defun xwl-sawfish-mode-hook ()
  (local-set-key (kbd "C-c <f1>  i")   'sawfish-info)
  (local-set-key (kbd "C-c <f1>  C-v") 'sawfish-info-variable)
  (local-set-key (kbd "C-c <f1>  v")   'sawfish-describe-variable)
  (local-set-key (kbd "C-c <f1>  C-f") 'sawfish-info-function)
  (local-set-key (kbd "C-c <f1>  f")   'sawfish-describe-function)
  (local-set-key (kbd "C-c <f1>  a")   'sawfish-apropos)

  (local-set-key (kbd "ESC TAB") 'sawfish-complete-symbol))

(add-hook 'sawfish-mode-hook 'xwl-sawfish-mode-hook)

;; ispell
(setq ispell-alternate-dictionary "/usr/share/dict/words")
;;      ispell-personal-dictionary "/home/william/.ispell_william")

;; (mapcar* '(lambda (hook) (add-hook hook 'ispell-message))
;; 	 '(
;; 	   message-send-hook
;; 	   mail-send-hook
;; 	   mh-before-send-letter-hook
;; 	   ))

;; RSS: newsticker

;; (setq newsticker-url-list-defaults
;;       '(("douban-tokyo-love-story" "http://www.douban.com/feed/group/11197/discussion")
;; 	("newsmth-blog" "http://www.newsmth.com/pc/rssrec.php")))

;; (global-set-key (kbd "C-c m n") 'newsticker-show-news)

;; (add-hook 'newsticker-mode-hook 'less-minor-mode-on)

;; *eshell*
;; --------
(defun xwl-eshell-mode-hook ()
  (local-set-key (kbd "C-a") '(lambda ()
                                (interactive)
                                (back-to-indentation)
                                (search-forward " " nil t 2)))
  (local-set-key (kbd "C-w") '(lambda ()
                                (interactive)
                                (let ((inhibit-read-only t))
                                  (call-interactively 'kill-region)))))

(add-hook 'eshell-mode-hook 'xwl-eshell-mode-hook)


;; Texinfo
;; -------
(require 'texinfo)
(setq makeinfo-run-command "~/repo/cvs/texinfo/makeinfo/makeinfo")
;; (define-key Texinfo-mode-map (kbd "C-c g c") 'makeinfo-buffer)
;; disable fill at all!
(setq makeinfo-options "--fill-column=999")
;; "--paragraph-indent=0")

;; same filename, different paths
(require 'uniquify)
(setq uniquify-buffer-name-style 'forward)

;; weather
;; -------
(setq xwl-weather-string "")
(setq xwl-weather-list nil)
(setq xwl-weather-checked-day nil)

(defun xwl-weather-update (&optional force)
  (interactive)
  (if (or force
          (null xwl-weather-checked-day)
          (> (string-to-number (format-time-string "%d" (current-time)))
             xwl-weather-checked-day))
      (progn
        (message "updating weather info...")
        (setq xwl-weather-checked-day
              (string-to-number (format-time-string "%d" (current-time))))
        (setq xwl-weather-list
              (remove
               ""
               (split-string
                (shell-command-to-string
                 "/home/william/repo/darcs/guile/scripts/weather-man.scm 北京")
                "\n")))
        (setq xwl-weather-string
              (replace-regexp-in-string
               "风力："
               ""
               (concat "["
                       (mapconcat (lambda (el) el)
                                  (remove
                                   ""
                                   (cdr (split-string (car xwl-weather-list) ";")))
                                  "")
                       "/"
                       (mapconcat (lambda (el) el)
                                  (remove
                                   ""
                                   (cdr (split-string (cadr xwl-weather-list) ";")))
                                  "")
                       "]")))
        (message "done"))
    (message "weather already up-to-date")))

;; (run-with-idle-timer (* 10 60) (* 24 60 60) 'xwl-weather-update)

(defun xwl-weather-show ()
  (interactive)
  (let ((str ""))
    (mapc (lambda (day) (setq str (concat str day "\n")))
          xwl-weather-list)
    (message str)))

(require 'webjump)
(global-set-key (kbd "C-c m w") 'webjump)

(mapc (lambda (el)
        (add-to-list 'webjump-sites el))
      '(("gentoo software search" . "http://www.rommel.stw.uni-erlangen.de/~fejf/pfs/")
        ("douban" . "http://www.douban.com")
        ("gmail" . "http://www.gmail.com")
        ("bloglines" . "http://www.bloglines.com/feeds")
        ("gitweb" . "http://git.savannah.gnu.org/gitweb/")
        ))


;;; Extra libs

(setq xwl-at-home-p t)

(require 'smart-operator)

(defun xwl-text-mode-hook ()
  (auto-compression-mode t)
  (abbrev-mode t)
  ;; (flyspell-mode t)

  (smart-operator-mode 1)
  (local-unset-key (kbd "."))
  ;; (local-set-key (kbd "M-S") 'wordnet-search)
  (local-set-key (kbd "M-s") 'dictionary-search)

  (local-unset-key (kbd "M-S")))
;; (local-set-key (kbd "TAB") 'ispell-complete-word))

(add-hook 'text-mode-hook 'xwl-text-mode-hook)

(when (fboundp 'browse-kill-ring)
  (require 'browse-kill-ring)
  (browse-kill-ring-default-keybindings)
  (global-set-key (kbd "M-y") 'browse-kill-ring))

;; ;; debian pkg manager
(autoload 'wajig "wajig" "Create a *wajig* buffer." t nil)

(setq wajig-frequent-commands
      '("ps -ef"
        "ps -u william u"
        "lsof -i -nP"))

(add-hook 'wagjig-mode-hook
          (lambda ()
            (define-key wajig-mode-map (kbd "RET")
              (lambda () (interactive)
                (if (ffap-file-at-point)
                    (ffap (ffap-file-at-point))
                  (wajig-show-at-point))))))

(setq wajig-command-prefix '("ssh"
                             ;; "192.168.234.130"
                             "ananas"
                             ))

;; gentoo

;; (autoload 'gentoo "gentoo" "Create a *gentoo* buffer." t nil)

;; (add-hook 'gentoo-mode-hook 'less-minor-mode-on)

(autoload 'fink "fink" "Create a *fink* buffer." t nil)

(add-hook 'fink-mode-hook 'less-minor-mode-on)


;;; Buffer - ibuffer, ido, midnight, session, savespace, recentf,
;;;          minibuffer

(setq xwl-hated-buffers
      '("*info*" "*Bookmark List*" "*scratch*" "*Compile-Log*"
	"*Completions*" "do" "*Occur*" ".diary" ".bbdb" "*desktop*"
	"*Playlist*" "*Messages*" "*compilation*" "*Ediff Registry*"
	"*Kill Ring*" "*Shell Command Output*" "*Holidays*"
	"*Help*" "*Async Shell Command*" ".newsrc-dribble"
	"*Calendar*" "*eshell*"))

;;;; ibuffer
;; ---------

(require 'ibuffer)
;; (global-set-key (kbd "C-x C-b") 'ibuffer)
(setq ibuffer-fontification-level t)
(setq ibuffer-never-show-regexps nil)

(setq ibuffer-formats
      '((mark modified read-only
	      " " (name 16 -1)
	      " " (mode 16 16)
	      " " (size 6 -1 :right)
	      " " filename) (mark " " (name 16 -1) " " filename)))

(defun xwl-ibuffer-forward-line ()
  (interactive)
  (ibuffer-forward-line)
  (ibuffer-visit-buffer-other-window-noselect))

(defun xwl-ibuffer-backward-line ()
  (interactive)
  (ibuffer-backward-line)
  (ibuffer-visit-buffer-other-window-noselect))

(defun xwl-ibuffer ()
  (interactive)
  (split-window-horizontally -25)
  (windmove-right)
  (ibuffer)
  (ibuffer-do-sort-by-major-mode))

(defun xwl-ibuffer-quit ()
  (interactive)
  (ibuffer-quit)
  (xwl-hide-buffer))

;; (global-set-key (kbd "<f4>") 'xwl-ibuffer)

(define-key ibuffer-mode-map (kbd "n") 'xwl-ibuffer-forward-line)
(define-key ibuffer-mode-map (kbd "p") 'xwl-ibuffer-backward-line)
(define-key ibuffer-mode-map (kbd "q") 'xwl-ibuffer-quit)

(setq ibuffer-saved-filters
      `(("mail"
	 ((or (mode . message-mode)
	      (mode . mail-mode)
	      (mode . gnus-group-mode)
	      (mode . gnus-summary-mode)
	      (mode . gnus-article-mode))))
	("lisp"
	 ((or (mode . lisp-mode)
	      (mode . emacs-lisp-mode)
	      (mode . lisp-interaction-mode)
	      (mode . sawfish-mode)
	      (mode . scheme-mode)
	      (mode . inferior-scheme-mode)
	      (mode . log-edit-mode))))
	("c_c++"
	 ((or (mode . c-mode)
	      (mode . c++-mode)
	      (mode . makefile-mode)
	      (mode . makefile-gmake-mode))))
	("java"
	 ((mode . java-mode)))
	("dired"
	 ((mode . dired-mode)))
	("web"
	 ((or (mode . sql-mode)
	      (mode . sql-interactive-mode)
	      (mode . php-mode)
	      (mode . html-mode)
	      (mode . css-mode)
	      (filename . "\\*SQL\\*"))))
	("help"
	 ((or (mode . help-mode)
	      (mode . apropos-mode)
	      (mode . Info-mode)
	      (mode . Man-mode)
	      (mode . woman-mode)
	      (mode . custom-mode))))
	("text"
	 ((or (mode . text-mode)
	      (mode . outline-mode)
	      (mode . muse-mode)
	      (mode . tex-mode)
	      (mode . latex-mode)
	      (mode . metapost-mode))))
	("process"
	 ((or (mode . comint-mode)
	      (mode . compilation-mode)
	      (mode . internal-ange-ftp-mode)
	      (mode . term-mode)
	      (mode . eshell-mode))))
	("erc"
	 ((mode . erc-mode)))
	("hated"
	 ((name . ,(regexp-opt xwl-hated-buffers))
	  (mode . fundamental-mode)))))

;;;; ido
;; -----
(setq ido-create-new-buffer 'never
      ido-enable-regexp nil)

;; 1. if no visible match, will match against ignored buffers.
;; 2. one can also toggle this by C-a
(setq ido-ignore-buffers
      '("\\*.+\\*" ".diary" ".scratch"
        "^#" "^localhost:" "&bitlbee"
        "\\.newsrc"))

;; C-k: killing buffers/files while idoing

(ido-mode 1)
(ido-everywhere 1)

(defadvice ido-find-file (around change-default-directory activate)
  "With a prefix argument, you can set `default-directory'."
  (let ((default-directory default-directory))
    (when current-prefix-arg
      (setq default-directory
            (ido-completing-read "Set default directory to: "
                                 xwl-default-directories)))
    ad-do-it))

(global-set-key (kbd "C-x C-f") 'ido-find-file)

;; by Andreas Politz <politza@fh-trier.de>
(require 'ido-hacks)
(ido-hacks-mode 1)

;; (require 'midnight)
;; ;; Setting this variable outside customize has no effect
;; ;; (setq midnight-mode t)
;; (setq clean-buffer-list-kill-never-buffer-names
;;       '("*Messages*" ".scratch" ".xwl-emacs.el" ".xwl_diary"))

;; session
;; * In the minibuffer, enter <M-?> to display a completion list with
(setq session-initialize t)
(setq session-globals-exclude
      '(load-history register-alist vc-comment-ring
		     flyspell-auto-correct-ring
		     planner-browser-file-display-rule-ring)
      session-globals-regexp "-\\(ring\\|history\\)\\'")

;; save cursor's place
(require 'saveplace)
(setq-default save-place t)

;; recentf
(recentf-mode 1)

(defun xwl-recentf-open-files ()
  (interactive)
  (let* ((alist (mapcar '(lambda (el)
                           (cons (file-name-nondirectory el) el))
                        recentf-list))
         (filename (ido-completing-read "Open recent file: "
                                        (mapcar 'car alist))))
    (find-file (cdr (assoc filename alist)))))

(global-set-key (kbd "C-c F") 'xwl-recentf-open-files)

;; (add-hook 'kill-emacs-hook 'recentf-cleanup)

(add-to-list 'recentf-keep 'file-remote-p)

(add-hook 'minibuffer-setup-hook 'turn-off-auto-fill)


;;; Bindings - keyboard bindings

;; scroll up and down
(defun xwl-scroll-down-one-line (&optional arg)
  "Scroll text of current window down ARG lines; or 1 line if no ARG."
  (interactive "P")
  (scroll-down (if arg (prefix-numeric-value arg) 1)))

(defun xwl-scroll-up-one-line (&optional arg)
  "Scroll text of current window up ARG lines; or 1 line if no ARG."
  (interactive "P")
  (scroll-up (if arg (prefix-numeric-value arg) 1)))

(defun xwl-scroll-other-window-down-one-line (&optional arg)
  "Scroll text of other window down ARG lines; or 1 line if no ARG."
  (interactive "P")
  (scroll-other-window (if arg (prefix-numeric-value arg) -1)))

(defun xwl-scroll-other-window-up-one-line (&optional arg)
  "Scroll text of other window up ARG lines; or 1 line if no ARG."
  (interactive "P")
  (scroll-other-window (if arg (prefix-numeric-value arg) 1)))

(global-set-key (kbd "M-p") 'xwl-scroll-down-one-line)
(global-set-key (kbd "M-n") 'xwl-scroll-up-one-line)

;; am i weird or Emacs is weird ?
(global-set-key (kbd "C-x <left>") 'next-buffer)
(global-set-key (kbd "C-x <right>") 'previous-buffer)

(global-set-key (kbd "C-<left>")  'previous-error)
(global-set-key (kbd "C-<right>") 'next-error)

;; conflicts

(dolist (hook '(dired-mode-hook
                calendar-move-hook
                gnus-summary-mode-hook
                gnus-group-mode-hook
                clone-buffer-hook))
  (add-hook hook
            (lambda ()
		   (if (not (one-window-p))
		       (local-set-key (kbd "<end>")
                                      'xwl-scroll-other-window-up-one-line))
		   (local-set-key (kbd "M-n") 'xwl-scroll-up-one-line)
		   (local-set-key (kbd "M-p") 'xwl-scroll-down-one-line))))

(add-hook 'w3m-mode-hook
	  (lambda ()
	    (local-set-key (kbd "M-n") 'xwl-scroll-up-one-line)
	    (local-set-key (kbd "M-p") 'xwl-scroll-down-one-line)
	    (local-set-key (kbd "<left>") 'w3m-previous-buffer)
	    (local-set-key (kbd "<right>") 'w3m-next-buffer)
	    (local-set-key (kbd "p") 'w3m-previous-buffer)
	    (local-set-key (kbd "n") 'w3m-next-buffer)
	    (local-set-key (kbd "c") 'w3m-delete-buffer)))

(add-hook 'makefile-mode-hook
	  '(lambda ()
	     (local-set-key (kbd "M-n") 'xwl-scroll-up-one-line)
	     (local-set-key (kbd "M-p") 'xwl-scroll-down-one-line)))

(global-set-key (kbd "C-c n t") 'toggle-truncate-lines)

(global-set-key (kbd "C-c m k") 'kill-this-buffer)

(global-set-key (kbd "C-x v =") 'ediff-revision)
(global-set-key (kbd "C-c m D") 'toggle-debug-on-error)

(require 'image-mode)
(define-key image-mode-map (kbd "l") 'image-forward-hscroll)
(define-key image-mode-map (kbd "h") 'image-backward-hscroll)

;; completion
;; (partial-completion-mode 1)

(defun xwl-kill-emacs-hook ()
  (when (fboundp 'gnus-group-exit)
    (gnus-group-exit)))

(add-hook 'kill-emacs-hook 'xwl-kill-emacs-hook)

(defadvice save-buffers-kill-emacs (before remove-less)
  "Remove `less-minor-mode-on' from `find-file-hook' while exiting."
  (remove-hook 'find-file-hook 'less-minor-mode-on))

(ad-activate 'save-buffers-kill-emacs)

;; (require 'auto-enca)
;; (modify-coding-system-alist 'file "" 'enca-detect-coding)


;;; POST

;; (set-default-font "10x20")

;; (defalias 'w3m-safe-view-this-url 'browse-url-at-point)
;; (defalias 'w3m-view-this-url 'browse-url-at-point)

; (toggle-debug-on-error)

;; (require 'gds)
;; (gds-run-debug-server)                  ; force it to run
;; (global-set-key (kbd "<f1> g") 'gds-help-symbol)

(global-unset-key (kbd "C-x C-b"))

;; See `xwl-start-main.el' and `xwl-start-gnus.el' for next loadup
;; step.

(defun xwl-check-holidays ()
  (calendar)
  (with-current-buffer "*Calendar*"
    (or (ignore-errors (diary-view-entries))
        (when (check-calendar-holidays (calendar-current-date))
          (calendar-cursor-holidays)))))

(defun xwl-running-daily ()
  "Staffs to run daily."
  (xwl-check-holidays)
  (plan))

;; timer when idle
(setq xwl-run-when-idle-hook nil)  ; Functions to run when Emacs is idle.

(add-hook 'xwl-run-when-idle-hook 'xwl-fortune-of-the-day)

;; (set-default-font "10x20")

(global-set-key (kbd "M-S") 'xwl-search-jp)

;; (setq visible-bell 'ignore)
(setq visible-bell nil)
(setq ring-bell-function 'ignore)

(keyboard-translate ?\C-h ?\C-?)

;; deal with japanese keyboard
(keyboard-translate ?\¥ ?\\)
(global-set-key (kbd "M-¥") (kbd "M-\\"))
(global-set-key (kbd "C-¥") 'hippie-expand)
(global-set-key (kbd "C-x C-¥") 'goto-last-change)
(global-set-key (kbd "C-M-¥") 'indent-region)

(global-auto-revert-mode 1)

(show-paren-mode 1)
(setq show-paren-style 'expression)

(global-set-key (kbd "C-\\") 'hippie-expand)
(global-set-key (kbd "C-2") 'set-mark-command)

(transient-mark-mode 1)

(global-set-key (kbd "C--") 'undo)

(global-set-key (kbd "C-c m s") '(lambda () (interactive) (find-file "~/.scratch")))

(global-set-key (kbd "C-c m r") 'revert-buffer)

(fset 'yes-or-no-p 'y-or-n-p)


;;;; misc
(setq kill-ring-max 100
      inhibit-startup-message t
      max-lisp-eval-depth 20000
      c-echo-syntactic-information-p nil)

(put 'set-goal-column 'disabled nil)
(put 'narrow-to-region 'disabled nil)
(put 'upcase-region 'disabled nil)
(put 'downcase-region 'disabled nil)
(put 'LaTeX-hide-environment 'disabled nil)
(put 'overwrite-mode 'disabled t)
(setq require-final-newline 't)
(setq-default truncate-lines t
	      truncate-partial-width-windows t)

;; transpose(interchange) two windows
(defun his-transpose-windows (arg)
  "Transpose the buffers shown in two windows."
  (interactive "p")
  (let ((selector (if (>= arg 0) 'next-window 'previous-window)))
    (while (/= arg 0)
      (let ((this-win (window-buffer))
	    (next-win (window-buffer (funcall selector))))
	(set-window-buffer (selected-window) next-win)
	(set-window-buffer (funcall selector) this-win)
	(select-window (funcall selector)))
      (setq arg (if (plusp arg) (1- arg) (1+ arg))))))

(global-set-key (kbd "C-c m t") 'his-transpose-windows)

(defun xwl-revert-buffer-with-sudo ()
  "Revert buffer using tramp sudo.
This will also reserve changes already made by a non-root user."
  (interactive)
  (let ((f (buffer-file-name)))
    (when f
      (let ((content (when (buffer-modified-p)
                       (widen)
                       (buffer-string))))
        (if (file-writable-p f)
            (revert-buffer)
          (kill-buffer (current-buffer))
          (if (file-remote-p f)
              (find-file
               (replace-regexp-in-string "^\\/[^:]+:" "/sudo:" f))
            (find-file (concat "/sudo::" f)))
          (when content
            (let ((buffer-read-only nil))
              (erase-buffer)
              (insert content))))))))

(global-set-key (kbd "C-c m R") 'xwl-revert-buffer-with-sudo)

;; use whitespaces instead of \t
(setq-default indent-tabs-mode nil)

;; save bookmark ASAP
(defadvice bookmark-set (after xwl-save-bookmark-now activate)
  (bookmark-save))

;; FIXME: w32 上中文星期显示为乱码？
(if (eq window-system 'w32)
    (setq display-time-format "<%V-%u> %m/%d/%H:%M")
  (setq display-time-format "%a %m/%d/%H:%M"))

(display-time)

(setq history-delete-duplicates t)


(mapc (lambda (el)
        (add-to-list 'auto-mode-alist el))
      '(("^/etc/conf.d" . conf-mode)
        ("\\.cnf$" . conf-mode)
        ("\\.ebuild$" . shell-script-mode)
        ))

(when (< emacs-major-version 23)
  (require 'page-break)
  (turn-on-page-break-mode))

(add-hook 'auto-mode-alist
          `(,(regexp-opt '(".todo"  ".ce_todo")) . easy-todo-mode))

(setq default-major-mode 'text-mode)

(add-hook 'auto-mode-alist '("\\.d$" . shell-script-mode))

(defadvice forward-page (after forward-page-and-first-column activate)
  (move-beginning-of-line nil))

;; control+英数(jis_esiuu)+p is missing on my macbook! :(
(global-set-key (kbd "C-M-@") (kbd "C-M-p"))

;; (add-hook 'kill-emacs-hook
;;           '(lambda ()
;;              (message "Byte compiling site-lisp...")
;;              (sleep-for 1)
;;              (if (zerop (shell-command "cd ~/.emacs.d/site-lisp; make; cd -"))
;;                  (message "Byte compiling site-lisp...succeeded")
;;                (message "Byte compiling site-lisp...failed")
;;                (when (y-or-n-p "Byte compiling site-lisp failed, back to emacs? ")
;;                  (keyboard-quit)))))

(when (fboundp 'tramp-cleanup-all-buffers)
  (add-hook 'kill-emacs-hook 'tramp-cleanup-all-buffers))

(setq split-width-threshold 150)

(provide 'xwl-convenience)

;;; xwl-convenience.el ends here
